# src/buildmcp/services/wp_sdk.py
import asyncio
import logging
from typing import Any, Optional, Dict
import httpx

class WeatherPerceptionSDK:
    """
    weather-perception API 异步 SDK 封装。
    支持自动重试，指数退避策略。
    Args:
        config (dict): 配置字典，例如：
            {
                "base_url": "",
                "api_key": "",
                "proxy": None,
                "max_retries": 5,
                "retry_delay": 1,
                "backoff_factor": 2,
            }
        logger (logging.Logger, optional): 日志记录器，默认使用模块 logger。
    """

    def __init__(self, config: dict, logger=None):
        self.api_key = config.get("api_key", "")
        self.base_url = config.get("base_url", "").rstrip('/')
        self.proxy = config.get("proxy", None)
        self.logger = logger or logging.getLogger(__name__)
        self.max_retries = config.get("max_retries", 5)
        self.retry_delay = config.get("retry_delay", 1)
        self.backoff_factor = config.get("backoff_factor", 2)
        self._client = httpx.AsyncClient(proxy=self.proxy, timeout=10)

    async def __aenter__(self):
        return self

    async def __aexit__(self, exc_type, exc, tb):
        await self._client.aclose()

    def _should_retry(self, response: httpx.Response = None, exception: Exception = None) -> bool:
        if exception is not None:
            return True
        if response is not None and response.status_code in (429, 500, 502, 503, 504):
            return True
        return False

    async def _request_with_retry(self, method: str, url: str, params=None, json=None):
        for attempt in range(self.max_retries + 1):
            try:
                self.logger.info(f"发送请求：{method} {url}，参数：{params}, JSON：{json}, 尝试次数：{attempt + 1}/{self.max_retries + 1}")
                response = await self._client.request(
                    method=method,
                    url=url,
                    params=params,
                    json=json,
                )
                self.logger.info(f"收到响应：{response.status_code} {response.text}")
                if response.status_code in [200, 201]:
                    return response.json()
                if not self._should_retry(response=response):
                    self.logger.error(f"请求失败且不可重试，状态码：{response.status_code}，URL：{url}")
                    return None
                self.logger.warning(
                    f"请求失败（状态码：{response.status_code}），"
                    f"第 {attempt + 1}/{self.max_retries} 次重试，URL：{url}"
                )
            except httpx.RequestError as e:
                self.logger.warning(
                    f"请求异常：{str(e)}，"
                    f"第 {attempt + 1}/{self.max_retries} 次重试，URL：{url}"
                )
            if attempt < self.max_retries:
                delay = self.retry_delay * (self.backoff_factor ** attempt)
                await asyncio.sleep(delay)
        self.logger.error(f"所有重试失败，URL：{url}")
        return None

    async def query_station(
        self,
        devicename: str,
        page_num: int = 1,
        page_size: int = 240,
    ) -> Optional[Dict[str, Any]]:
        """
        查询指定站点的 weather-perception 数据
        Args:
            devicename (str): 站点编号
            page_num (int, optional): 页码，默认 1
            page_size (int, optional): 每页条数，默认 240
        Returns:
            dict | None: 查询结果，失败时返回 None
        """
        url = self.base_url  # 如果还有 /api/path 需要加上
        params = {
            "devicename": devicename,
            "pageNum": page_num,
            "pageSize": page_size,
        }
        if self.api_key:
            params["key"] = self.api_key  # 如需鉴权
        result = await self._request_with_retry(
            method="Post",
            url=url,
            json=params,
        )
        # 你可以按实际接口判断 success 或 data 字段
        if result:
            return result
        else:
            self.logger.error(f"查询站点数据失败: {result}")
            return None

    async def close(self):
        await self._client.aclose()
